<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

   <!-- 百度联盟 -->
   <meta name="baidu_union_verify" content="46e227ad81d5513c6cd8288c18c6ebad">

   <!-- google analytics -->
   <meta name="google-site-verification" content="SzCGQVmA8Mtk40elee-bCGpq2YSCAmEulSNEZHYCkFc" />

   <!--百度站长之家验证-->
   <meta name="baidu-site-verification" content="4woRik4rfk" />

   <meta name="description" content="坑要一个个填，路要一步步走！—— from zhisheng的博客">
   <meta name="keywords" content="Java,架构,后端,服务端,RocketMQ,分布式消息队列,分布式存储,技术博客,HBase,ElasticSearch,Spring,Spring Boot,Spring Boot 2.0,Spring Cloud,Spring MVC,Java EE,前端,HTML,MyBatis,Android,Docker,Mac,Consul,Kafka,Logstash,Kibana,MySQL,Maven,Nginx,Python,RabbitMQ,ActiveMQ,JVM">


  <title>Spring Boot 2.0系列文章(七)：SpringApplication 深入探索 | zhisheng的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="keywords" content="Java,SpringBoot">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring Boot 2.0系列文章(七)：SpringApplication 深入探索">
<meta property="og:url" content="http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/index.html">
<meta property="og:site_name" content="zhisheng的博客">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://ws3.sinaimg.cn/large/006tKfTcgy1fqxbkmfds2j31hc0oegze.jpg">
<meta property="og:image" content="http://image.54tianzhisheng.cn/blog/180103/C6LG3mGa12.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tttpf2j312618mn4w.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tz1wmyj31kw1f3qeo.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tuvk6lj31kw1a6qio.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tvo4l3j31ke1fads1.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tyfizgj31be13ujws.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tmcuslj31im0yigtw.jpg">
<meta property="og:image" content="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6xo1yhjj31kw1cinbe.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tt63ojj31kw0kotk4.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6ty24gvj31kw0l3n7h.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6u0khy1j31kw0wuhar.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqxei8t4u6j31do0ow0z9.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tx7lchj31kw0nw4gr.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tp9y81j31kw0tfdqv.jpg">
<meta property="og:image" content="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6tli7pjj31kw1757h0.jpg">
<meta property="og:image" content="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6xir0iaj31kw0urjuy.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tr2ukqj31je1fegwm.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6xjtn0hj31ja17g15o.jpg">
<meta property="og:image" content="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6toc4dxj31kw1bana4.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tnnz8vj31bs0pkgrg.jpg">
<meta property="og:image" content="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6ts33l2j31kw0witww.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6xmgbpvj31kw0x8hc4.jpg">
<meta property="og:image" content="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tq6fzhj31kw0y5azk.jpg">
<meta property="og:image" content="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6xla7afj31kw0unx1j.jpg">
<meta property="og:updated_time" content="2018-11-22T14:51:57.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Spring Boot 2.0系列文章(七)：SpringApplication 深入探索">
<meta name="twitter:image" content="https://ws3.sinaimg.cn/large/006tKfTcgy1fqxbkmfds2j31hc0oegze.jpg">
  
    <link rel="alternative" href="/atom.xml" title="zhisheng的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/img/favicon.ico">
  
  
      <link rel="stylesheet" href="//cdn.bootcss.com/animate.css/3.5.0/animate.min.css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/font-awesome/css/font-awesome.min.css">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  
  
      <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  
  <!-- 加载特效 -->
  <script src="/js/pace.js"></script>
  <link href="/css/pace/pace-theme-flash.css" rel="stylesheet" />
  <script>
      var yiliaConfig = {
          rootUrl: '/',
          fancybox: true,
          animate: true,
          isHome: false,
          isPost: true,
          isArchive: false,
          isTag: false,
          isCategory: false,
          open_in_new: true
      }
  </script>
</head>
<body>
  <div id="container">
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
    <header id="header" class="inner">
        <a href="/" class="profilepic">
            
            <img lazy-src="/img/avatar.png" class="js-avatar">
            
        </a>

        <hgroup>
          <h1 class="header-author"><a href="/">zhisheng</a></h1>
        </hgroup>

        
        <p class="header-subtitle">坑要一个个填，路要一步步走！</p>
        
        
        
            <div id="switch-btn" class="switch-btn">
                <div class="icon">
                    <div class="icon-ctn">
                        <div class="icon-wrap icon-house" data-idx="0">
                            <div class="birdhouse"></div>
                            <div class="birdhouse_holes"></div>
                        </div>
                        <div class="icon-wrap icon-ribbon hide" data-idx="1">
                            <div class="ribbon"></div>
                        </div>
                        
                        <div class="icon-wrap icon-link hide" data-idx="2">
                            <div class="loopback_l"></div>
                            <div class="loopback_r"></div>
                        </div>
                        
                        
                        <div class="icon-wrap icon-me hide" data-idx="3">
                            <div class="user"></div>
                            <div class="shoulder"></div>
                        </div>
                        
                    </div>
                    
                </div>
                <div class="tips-box hide">
                    <div class="tips-arrow"></div>
                    <ul class="tips-inner">
                        <li>菜单</li>
                        <li>标签</li>
                        
                        <li>友情链接</li>
                        
                        
                        <li>关于我</li>
                        
                    </ul>
                </div>
            </div>
        

        <div id="switch-area" class="switch-area">
            <div class="switch-wrap">
                <section class="switch-part switch-part1">
                    <nav class="header-menu">
                        <ul>
                        
                            <li><a href="/">主页</a></li>
                        
                            <li><a href="/tags/Flink/">Flink</a></li>
                        
                            <li><a href="/tags/ElasticSearch/">ElasticSearch</a></li>
                        
                            <li><a href="/tags/SpringBoot/">Spring Boot</a></li>
                        
                        </ul>
                    </nav>
                    <nav class="header-nav">
                        <ul class="social">
                            
                                <a class="fl wechat" target="_blank" href="wechat:zhisheng_tian" title="wechat">wechat</a>
                            
                                <a class="fl mail" target="_blank" href="mailto://zhisheng2018@gmail.com" title="mail">mail</a>
                            
                                <a class="fl github" target="_blank" href="https://github.com/zhisheng17/" title="github">github</a>
                            
                                <a class="fl zhihu" target="_blank" href="https://www.zhihu.com/people/tian-zhisheng/activities" title="zhihu">zhihu</a>
                            
                        </ul>
                    </nav>
                </section>
                
                
                <section class="switch-part switch-part2">
                    <div class="widget tagcloud" id="js-tagcloud">
                        <a href="/tags/AJAX/" style="font-size: 10px;">AJAX</a> <a href="/tags/ActiveMQ/" style="font-size: 10px;">ActiveMQ</a> <a href="/tags/Android/" style="font-size: 10px;">Android</a> <a href="/tags/Bootstrap/" style="font-size: 13px;">Bootstrap</a> <a href="/tags/Consul/" style="font-size: 10px;">Consul</a> <a href="/tags/Docker/" style="font-size: 11px;">Docker</a> <a href="/tags/ElasticSearch/" style="font-size: 17px;">ElasticSearch</a> <a href="/tags/Filter过滤器/" style="font-size: 10px;">Filter过滤器</a> <a href="/tags/Flink/" style="font-size: 18px;">Flink</a> <a href="/tags/GO/" style="font-size: 10px;">GO</a> <a href="/tags/Github-Page/" style="font-size: 10px;">Github Page</a> <a href="/tags/Guava/" style="font-size: 10px;">Guava</a> <a href="/tags/HBase/" style="font-size: 10px;">HBase</a> <a href="/tags/Hibernate-JPA/" style="font-size: 11px;">Hibernate JPA</a> <a href="/tags/IO/" style="font-size: 11px;">IO</a> <a href="/tags/JMM/" style="font-size: 10px;">JMM</a> <a href="/tags/JSON/" style="font-size: 10px;">JSON</a> <a href="/tags/JVM/" style="font-size: 11px;">JVM</a> <a href="/tags/Java/" style="font-size: 20px;">Java</a> <a href="/tags/Kafka/" style="font-size: 12px;">Kafka</a> <a href="/tags/Kibana/" style="font-size: 10px;">Kibana</a> <a href="/tags/LogStash/" style="font-size: 10px;">LogStash</a> <a href="/tags/Mac/" style="font-size: 10px;">Mac</a> <a href="/tags/Maven/" style="font-size: 11px;">Maven</a> <a href="/tags/MySQL/" style="font-size: 12px;">MySQL</a> <a href="/tags/Mybatis/" style="font-size: 14px;">Mybatis</a> <a href="/tags/NIO/" style="font-size: 10px;">NIO</a> <a href="/tags/Netty/" style="font-size: 10px;">Netty</a> <a href="/tags/Nginx/" style="font-size: 11px;">Nginx</a> <a href="/tags/Oracle/" style="font-size: 10px;">Oracle</a> <a href="/tags/Pyspider/" style="font-size: 10px;">Pyspider</a> <a href="/tags/Python/" style="font-size: 12px;">Python</a> <a href="/tags/RabbitMQ/" style="font-size: 11px;">RabbitMQ</a> <a href="/tags/Redis/" style="font-size: 11px;">Redis</a> <a href="/tags/RocketMQ/" style="font-size: 13px;">RocketMQ</a> <a href="/tags/Servlet/" style="font-size: 10px;">Servlet</a> <a href="/tags/Spring/" style="font-size: 12px;">Spring</a> <a href="/tags/Spring-MVC/" style="font-size: 15px;">Spring MVC</a> <a href="/tags/SpringBoot/" style="font-size: 19px;">SpringBoot</a> <a href="/tags/SpringCloud/" style="font-size: 10px;">SpringCloud</a> <a href="/tags/SpringMVC/" style="font-size: 13px;">SpringMVC</a> <a href="/tags/String/" style="font-size: 10px;">String</a> <a href="/tags/Velocity/" style="font-size: 10px;">Velocity</a> <a href="/tags/Zookeeper/" style="font-size: 10px;">Zookeeper</a> <a href="/tags/finally/" style="font-size: 10px;">finally</a> <a href="/tags/foreach/" style="font-size: 10px;">foreach</a> <a href="/tags/hexo/" style="font-size: 12px;">hexo</a> <a href="/tags/lombok/" style="font-size: 10px;">lombok</a> <a href="/tags/lua/" style="font-size: 10px;">lua</a> <a href="/tags/yilia/" style="font-size: 11px;">yilia</a> <a href="/tags/书籍/" style="font-size: 10px;">书籍</a> <a href="/tags/分布式锁/" style="font-size: 10px;">分布式锁</a> <a href="/tags/前端/" style="font-size: 12px;">前端</a> <a href="/tags/励志/" style="font-size: 10px;">励志</a> <a href="/tags/博客合集/" style="font-size: 10px;">博客合集</a> <a href="/tags/博客网站/" style="font-size: 10px;">博客网站</a> <a href="/tags/多线程/" style="font-size: 11px;">多线程</a> <a href="/tags/大数据/" style="font-size: 18px;">大数据</a> <a href="/tags/字符串/" style="font-size: 11px;">字符串</a> <a href="/tags/实习圈/" style="font-size: 10px;">实习圈</a> <a href="/tags/循环队列/" style="font-size: 10px;">循环队列</a> <a href="/tags/微服务/" style="font-size: 11px;">微服务</a> <a href="/tags/性能调优工具/" style="font-size: 10px;">性能调优工具</a> <a href="/tags/投资理财/" style="font-size: 10px;">投资理财</a> <a href="/tags/数据库/" style="font-size: 12px;">数据库</a> <a href="/tags/数据结构/" style="font-size: 13px;">数据结构</a> <a href="/tags/文件/" style="font-size: 10px;">文件</a> <a href="/tags/旋转词/" style="font-size: 10px;">旋转词</a> <a href="/tags/流式计算/" style="font-size: 18px;">流式计算</a> <a href="/tags/流控/" style="font-size: 10px;">流控</a> <a href="/tags/爬虫/" style="font-size: 12px;">爬虫</a> <a href="/tags/算法/" style="font-size: 12px;">算法</a> <a href="/tags/类加载机制/" style="font-size: 10px;">类加载机制</a> <a href="/tags/线程池/" style="font-size: 10px;">线程池</a> <a href="/tags/编码/" style="font-size: 10px;">编码</a> <a href="/tags/表达式/" style="font-size: 10px;">表达式</a> <a href="/tags/邮件发送/" style="font-size: 10px;">邮件发送</a> <a href="/tags/随笔/" style="font-size: 16px;">随笔</a> <a href="/tags/面经/" style="font-size: 16px;">面经</a>
                    </div>
                </section>
                
                
                
                <section class="switch-part switch-part3">
                    <div id="js-friends">
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://blog.csdn.net/tzs_1041218129">CSDN博客</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://juejin.im/user/57510b82128fe10056ca70fc">掘金</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.iocoder.cn/?vip">芋道源码</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://fengzhaofeng.net/">冯兆峯</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.codedata.cn/">CodeData</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://investguider.com/">美股指南</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.songyawei.cn/">Linux运维工程师</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.carlzone.cn/">carl.zhao</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://dongkelun.com/">伦少的博客</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.jiangxinlingdu.com/">匠心零度</a>
                    
                    </div>
                </section>
                

                
                
                <section class="switch-part switch-part4">
                
                    <div id="js-aboutme">17.08 ~ 18.05 永辉云创基础架构组实习     2018.06 大学毕业   2018.06 ～ 现在  另一家公司各种折腾!</div>
                </section>
                
            </div>
        </div>
        <div>
            <img src="/img/wx.jpg"  alt="zhisheng" />
        </div>
    </header>
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
      <div class="overlay">
          <div class="slider-trigger"></div>
          <h1 class="header-author js-mobile-header hide"><a href="/" title="Me">zhisheng</a></h1>
      </div>
    <div class="intrude-less">
        <header id="header" class="inner">
            <a href="/" class="profilepic">
                
                    <img lazy-src="/img/avatar.png" class="js-avatar">
                
            </a>
            <hgroup>
              <h1 class="header-author"><a href="/" title="Me">zhisheng</a></h1>
            </hgroup>
            
            <p class="header-subtitle">坑要一个个填，路要一步步走！</p>
            
            <nav class="header-menu">
                <ul>
                
                    <li><a href="/">主页</a></li>
                
                    <li><a href="/tags/Flink/">Flink</a></li>
                
                    <li><a href="/tags/ElasticSearch/">ElasticSearch</a></li>
                
                    <li><a href="/tags/SpringBoot/">Spring Boot</a></li>
                
                <div class="clearfix"></div>
                </ul>
            </nav>
            <nav class="header-nav">
                <div class="social">
                    
                        <a class="wechat" target="_blank" href="wechat:zhisheng_tian" title="wechat">wechat</a>
                    
                        <a class="mail" target="_blank" href="mailto://zhisheng2018@gmail.com" title="mail">mail</a>
                    
                        <a class="github" target="_blank" href="https://github.com/zhisheng17/" title="github">github</a>
                    
                        <a class="zhihu" target="_blank" href="https://www.zhihu.com/people/tian-zhisheng/activities" title="zhihu">zhihu</a>
                    
                </div>
            </nav>
        </header>                
    </div>
</nav>
      <div class="body-wrap"><article id="post-springboot_SpringApplication" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/2018/04/30/springboot_SpringApplication/" class="article-date">
      <time datetime="2018-04-29T16:00:00.000Z" itemprop="datePublished">2018-04-30</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Spring Boot 2.0系列文章(七)：SpringApplication 深入探索
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        

        
    <div class="article-tag tagcloud">
        <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/">Java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/SpringBoot/">SpringBoot</a></li></ul>
    </div>

        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
          
        <p><img src="https://ws3.sinaimg.cn/large/006tKfTcgy1fqxbkmfds2j31hc0oegze.jpg" alt="sunset-3325080_1920"></p>
<a id="more"></a>
<h3 id="关注我"><a href="#关注我" class="headerlink" title="关注我"></a>关注我</h3><p><img src="http://image.54tianzhisheng.cn/blog/180103/C6LG3mGa12.jpg" alt="mark"></p>
<p>转载请务必注明原创地址为：<a href="http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/">http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/</a></p>
<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>在 Spring Boot 项目的启动类中常见代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringbotApplication</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		SpringApplication.run(SpringbotApplication.class, args);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>其中也就两个比较引人注意的地方：</p>
<ul>
<li><code>@SpringBootApplication</code></li>
<li><code>SpringApplication.run()</code></li>
</ul>
<p>对于第一个注解 <code>@SpringBootApplication</code>，我已经在博客 <a href="http://www.54tianzhisheng.cn/2018/04/19/SpringBootApplication-annotation/">Spring Boot 2.0系列文章(六)：Spring Boot 2.0中SpringBootApplication注解详解</a> 中详细的讲解了。接下来就是深入探究第二个了 <code>SpringApplication.run()</code> 。</p>
<h3 id="换个姿势"><a href="#换个姿势" class="headerlink" title="换个姿势"></a>换个姿势</h3><p>上面的姿势太简单了，只一行代码就完事了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SpringApplication.run(SpringbotApplication.class, args);</span><br></pre></td></tr></table></figure>
<p>其实是支持做一些个性化的设置，接下来我们换个姿势瞧瞧：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringbotApplication</span> </span>&#123;  </span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		SpringApplication app = <span class="keyword">new</span> SpringApplication(SpringbotApplication.class);</span><br><span class="line"> 		<span class="comment">// 自定义应用程序的配置</span></span><br><span class="line"> 		<span class="comment">//app.setXxx()</span></span><br><span class="line"> 		app.run(args)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>没错，就是通过一个构造函数，然后设置相关的属性，从而达到定制化服务。有哪些属性呢？</p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tttpf2j312618mn4w.jpg" alt="SpringApplicationFileds"></p>
<p>属性对应的 get／set 方法</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tz1wmyj31kw1f3qeo.jpg" alt="springapplication_getset"></p>
<p>看到没，还很多呢！</p>
<p>举个例子：你想把 Spring Boot 项目的默认 Banner 换成你自己的，就需要在这里如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"><span class="comment">//		SpringApplication.run(Springboot2Application.class, args);</span></span><br><span class="line">  SpringApplication application = <span class="keyword">new</span> SpringApplication(Springboot2Application.class);</span><br><span class="line">  application.setBanner((environment, sourceClass, out) -&gt; &#123;</span><br><span class="line">    <span class="comment">//这里打印一个logo</span></span><br><span class="line">    System.out.println(<span class="string">"      _      _       _\n"</span> +</span><br><span class="line">                       <span class="string">"     | |    (_)     | |\n"</span> +</span><br><span class="line">                       <span class="string">" ____| |__   _  ___ | |__    ___  _ __    __ _\n"</span> +</span><br><span class="line">                       <span class="string">"|_  /| '_ \\ | |/ __|| '_ \\  / _ \\| '_ \\  / _` |\n"</span> +</span><br><span class="line">                       <span class="string">" / / | | | || |\\__ \\| | | ||  __/| | | || (_| |\n"</span> +</span><br><span class="line">                       <span class="string">"/___||_| |_||_||___/|_| |_| \\___||_| |_| \\__, |\n"</span> +</span><br><span class="line">                       <span class="string">"                                          __/ |\n"</span> +</span><br><span class="line">                       <span class="string">"                                         |___/\n"</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">  application.setBannerMode(Banner.Mode.CONSOLE);</span><br><span class="line">  <span class="comment">//你还可以干其他的定制化初始设置</span></span><br><span class="line">  application.run(args);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>现在重启项目，你就会发现，控制台的 logo 已经换成你自己的了。</p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tuvk6lj31kw1a6qio.jpg" alt="banner"></p>
<p>当然了，你可能会觉得这样写有点复杂，嗯嗯，确实，这样硬编码在代码里确实不太友好。你还可以在<code>src/main/resources</code>路径下新建一个<code>banner.txt</code>文件，<code>banner.txt</code>中填写好需要打印的字符串内容即可。</p>
<p>从该类中可以看到在 Spring Boot 2 中引入了个新的 WebApplicationType 和 WebEnvironment。</p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tvo4l3j31ke1fads1.jpg" alt="springapplication-002"></p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tyfizgj31be13ujws.jpg" alt="webapplicationtype"></p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tmcuslj31im0yigtw.jpg" alt="springapplication-003"></p>
<p>确实，这也是 Spring Boot 2 中比较大的特性，它是支持响应式编程的。我之前在文章 <a href="http://www.54tianzhisheng.cn/2018/03/06/SpringBoot2-new-features/">Spring Boot 2.0系列文章(二)：Spring Boot 2.0 新特性详解</a> 中也介绍过，以后有机会会介绍它的，这里我先卖个关子。</p>
<h3 id="SpringApplication-初始化"><a href="#SpringApplication-初始化" class="headerlink" title="SpringApplication 初始化"></a>SpringApplication 初始化</h3><p><code>SpringApplication.run()</code>  的实现才是我们要深入探究的主角，该方法代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//静态方法，可用于使用默认配置运行 SpringApplication</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(Class&lt;?&gt; primarySource,</span></span></span><br><span class="line"><span class="function"><span class="params">      String... args)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> run(<span class="keyword">new</span> Class&lt;?&gt;[] &#123; primarySource &#125;, args);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(Class&lt;?&gt;[] primarySources,</span></span></span><br><span class="line"><span class="function"><span class="params">			String[] args)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> SpringApplication(primarySources).run(args);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在这个静态方法中，创建 SpringApplication 对象，并调用该对象的 run 方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">SpringApplication</span><span class="params">(Class&lt;?&gt;... primarySources)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>(<span class="keyword">null</span>, primarySources);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//创建一个 SpringApplication 实例，应用上下文会根据指定的主要资源加载 beans ，实例在调用 run 方法之前可以定制化</span></span><br><span class="line"><span class="meta">@SuppressWarnings</span>(&#123; <span class="string">"unchecked"</span>, <span class="string">"rawtypes"</span> &#125;)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">SpringApplication</span><span class="params">(ResourceLoader resourceLoader, Class&lt;?&gt;... primarySources)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.resourceLoader = resourceLoader;</span><br><span class="line">  Assert.notNull(primarySources, <span class="string">"PrimarySources must not be null"</span>);</span><br><span class="line">  <span class="keyword">this</span>.primarySources = <span class="keyword">new</span> LinkedHashSet&lt;&gt;(Arrays.asList(primarySources));</span><br><span class="line">  <span class="keyword">this</span>.webApplicationType = deduceWebApplicationType();</span><br><span class="line">  setInitializers((Collection) getSpringFactoriesInstances(</span><br><span class="line">    ApplicationContextInitializer.class));</span><br><span class="line">  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));</span><br><span class="line">  <span class="keyword">this</span>.mainApplicationClass = deduceMainApplicationClass();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>首先是进入单个参数的构造方法，然后进入两参数的构造方法（ResourceLoader 为 null），然后进行初始化。</p>
<p><strong>1、deduceWebApplicationType()</strong> : 推断应用的类型 ，创建的是一个 SERVLET 应用还是 REACTIVE应用或者是 NONE</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String REACTIVE_WEB_ENVIRONMENT_CLASS = <span class="string">"org.springframework.web.reactive.DispatcherHandler"</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String MVC_WEB_ENVIRONMENT_CLASS = <span class="string">"org.springframework.web.servlet.DispatcherServlet"</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] WEB_ENVIRONMENT_CLASSES = &#123; <span class="string">"javax.servlet.Servlet"</span>,</span><br><span class="line">			<span class="string">"org.springframework.web.context.ConfigurableWebApplicationContext"</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> WebApplicationType <span class="title">deduceWebApplicationType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, <span class="keyword">null</span>)</span><br><span class="line">      &amp;&amp; !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, <span class="keyword">null</span>)) &#123;</span><br><span class="line">    <span class="keyword">return</span> WebApplicationType.REACTIVE;	<span class="comment">//该程序是 REACTIVE 程序</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> (String className : WEB_ENVIRONMENT_CLASSES) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!ClassUtils.isPresent(className, <span class="keyword">null</span>)) &#123;</span><br><span class="line">      <span class="keyword">return</span> WebApplicationType.NONE;	<span class="comment">//该程序为 NONE</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> WebApplicationType.SERVLET;	<span class="comment">//默认返回是 SERVLET 程序</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>2、setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))</strong>：初始化 classpath 下的所有的可用的 ApplicationContextInitializer。</p>
<p>1）、getSpringFactoriesInstances()</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> &lt;T&gt; <span class="function">Collection&lt;T&gt; <span class="title">getSpringFactoriesInstances</span><span class="params">(Class&lt;T&gt; type)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> getSpringFactoriesInstances(type, <span class="keyword">new</span> Class&lt;?&gt;[] &#123;&#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//获取所有的 Spring 工厂实例</span></span><br><span class="line"><span class="keyword">private</span> &lt;T&gt; <span class="function">Collection&lt;T&gt; <span class="title">getSpringFactoriesInstances</span><span class="params">(Class&lt;T&gt; type,</span></span></span><br><span class="line"><span class="function"><span class="params">Class&lt;?&gt;[] parameterTypes, Object... args)</span> </span>&#123;</span><br><span class="line">  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();</span><br><span class="line">  <span class="comment">// Use names and ensure unique to protect against duplicates</span></span><br><span class="line">  Set&lt;String&gt; names = <span class="keyword">new</span> LinkedHashSet&lt;&gt;(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); <span class="comment">//获取所有 Spring Factories 的名字</span></span><br><span class="line">  List&lt;T&gt; instances = createSpringFactoriesInstances(type, parameterTypes,</span><br><span class="line">                                                     classLoader, args, names);</span><br><span class="line">  AnnotationAwareOrderComparator.sort(instances); <span class="comment">//Spring 工厂实例排序</span></span><br><span class="line">  <span class="keyword">return</span> instances;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//根据读取到的名字创建对象（Spring 工厂实例）</span></span><br><span class="line"><span class="keyword">private</span> &lt;T&gt; <span class="function">List&lt;T&gt; <span class="title">createSpringFactoriesInstances</span><span class="params">(Class&lt;T&gt; type,</span></span></span><br><span class="line"><span class="function"><span class="params"> Class&lt;?&gt;[] parameterTypes, ClassLoader classLoader, Object[] args, Set&lt;String&gt; names)</span> </span>&#123;</span><br><span class="line">  List&lt;T&gt; instances = <span class="keyword">new</span> ArrayList&lt;&gt;(names.size());</span><br><span class="line">  <span class="keyword">for</span> (String name : names) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      Class&lt;?&gt; instanceClass = ClassUtils.forName(name, classLoader);</span><br><span class="line">      Assert.isAssignable(type, instanceClass);</span><br><span class="line">      Constructor&lt;?&gt; constructor = instanceClass.getDeclaredConstructor(parameterTypes);</span><br><span class="line">      T instance = (T) BeanUtils.instantiateClass(constructor, args);</span><br><span class="line">      instances.add(instance);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(</span><br><span class="line">        <span class="string">"Cannot instantiate "</span> + type + <span class="string">" : "</span> + name, ex);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> instances;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的 SpringFactoriesLoader.loadFactoryNames() ，是从  META-INF/spring.factories 的资源文件中，读取 key 为org.springframework.context.ApplicationContextInitializer 的 value。</p>
<p><img src="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6xo1yhjj31kw1cinbe.jpg" alt="springfactoriesloader"></p>
<p>而 spring.factories 的部分内容如下：</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tt63ojj31kw0kotk4.jpg" alt="2018-05-01_22-21-20"></p>
<p>可以看到，最近的得到的，是 ConfigurationWarningsApplicationContextInitializer，ContextIdApplicationContextInitializer，DelegatingApplicationContextInitializer，ServerPortInfoApplicationContextInitializer 这四个类的名字。</p>
<p>2）、setInitializers()：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setInitializers</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">			Collection&lt;? extends ApplicationContextInitializer&lt;?&gt;&gt; initializers)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.initializers = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">  <span class="keyword">this</span>.initializers.addAll(initializers);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>所以，这里 setInitializers() 所得到的成员变量 initializers 就被初始化为ConfigurationWarningsApplicationContextInitializer，ContextIdApplicationContextInitializer，DelegatingApplicationContextInitializer，ServerPortInfoApplicationContextInitializer 这四个类的对象组成的 list。</p>
<p><strong>3、setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))</strong>：初始化 classpath 下的所有的可用的 ApplicationListener。</p>
<p>1）、getSpringFactoriesInstances() 和上面的类似，但是它是从  META-INF/spring.factories 的资源文件中，获取到 key 为 org.springframework.context.ApplicationListener 的 value。</p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6ty24gvj31kw0l3n7h.jpg" alt="2018-05-01_22-33-56"></p>
<p>2）、setListeners()：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setListeners</span><span class="params">(Collection&lt;? extends ApplicationListener&lt;?&gt;&gt; listeners)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.listeners = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">  <span class="keyword">this</span>.listeners.addAll(listeners);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>所以，这里 setListeners() 所得到的成员变量 listeners 就被初始化为 ClearCachesApplicationListener，ParentContextCloserApplicationListener，FileEncodingApplicationListener，AnsiOutputApplicationListener ，ConfigFileApplicationListener，DelegatingApplicationListener，ClasspathLoggingApplicationListener，LoggingApplicationListener，LiquibaseServiceLocatorApplicationListener  这九个类的对象组成的 list。</p>
<p><strong>4、deduceMainApplicationClass()</strong> ：根据调用栈，推断出 main 方法的类名</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Class&lt;?&gt; deduceMainApplicationClass() &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    StackTraceElement[] stackTrace = <span class="keyword">new</span> RuntimeException().getStackTrace();</span><br><span class="line">    <span class="keyword">for</span> (StackTraceElement stackTraceElement : stackTrace) &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="string">"main"</span>.equals(stackTraceElement.getMethodName())) &#123;</span><br><span class="line">        <span class="keyword">return</span> Class.forName(stackTraceElement.getClassName());</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">    <span class="comment">// Swallow and continue</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="run-方法背后的秘密"><a href="#run-方法背后的秘密" class="headerlink" title="run 方法背后的秘密"></a>run 方法背后的秘密</h3><p>上面看完了构造方法后，已经初始化了一个 SpringApplication 对象，接下来调用其 run 方法，代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//运行 Spring 应用程序，创建并刷新一个新的 ApplicationContext</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(String... args)</span> </span>&#123;</span><br><span class="line">		StopWatch stopWatch = <span class="keyword">new</span> StopWatch();</span><br><span class="line">		stopWatch.start();</span><br><span class="line">		ConfigurableApplicationContext context = <span class="keyword">null</span>;</span><br><span class="line">		Collection&lt;SpringBootExceptionReporter&gt; exceptionReporters = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">		configureHeadlessProperty();</span><br><span class="line">		SpringApplicationRunListeners listeners = getRunListeners(args);</span><br><span class="line">		listeners.starting();</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			ApplicationArguments applicationArguments = <span class="keyword">new</span> DefaultApplicationArguments(</span><br><span class="line">					args);</span><br><span class="line">			ConfigurableEnvironment environment = prepareEnvironment(listeners,</span><br><span class="line">					applicationArguments);</span><br><span class="line">			configureIgnoreBeanInfo(environment);</span><br><span class="line">			Banner printedBanner = printBanner(environment);</span><br><span class="line">			context = createApplicationContext();</span><br><span class="line">			exceptionReporters = getSpringFactoriesInstances(</span><br><span class="line">					SpringBootExceptionReporter.class,</span><br><span class="line">					<span class="keyword">new</span> Class[] &#123; ConfigurableApplicationContext.class &#125;, context);</span><br><span class="line">			prepareContext(context, environment, listeners, applicationArguments,</span><br><span class="line">					printedBanner);</span><br><span class="line">			refreshContext(context);</span><br><span class="line">			afterRefresh(context, applicationArguments);</span><br><span class="line">			stopWatch.stop();</span><br><span class="line">			<span class="keyword">if</span> (<span class="keyword">this</span>.logStartupInfo) &#123;</span><br><span class="line">				<span class="keyword">new</span> StartupInfoLogger(<span class="keyword">this</span>.mainApplicationClass)</span><br><span class="line">						.logStarted(getApplicationLog(), stopWatch);</span><br><span class="line">			&#125;</span><br><span class="line">			listeners.started(context);</span><br><span class="line">			callRunners(context, applicationArguments);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">			handleRunFailure(context, ex, exceptionReporters, listeners);</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(ex);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			listeners.running(context);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">			handleRunFailure(context, ex, exceptionReporters, <span class="keyword">null</span>);</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(ex);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> context;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>可变个数参数 args 即是我们整个应用程序的入口 main 方法的参数。StopWatch 是来自 org.springframework.util 的工具类，可以用来方便的记录程序的运行时间。</p>
<p>再来看看 1.5.12 与 2.0.1 版本的 run 方法 有什么不一样的地方？</p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6u0khy1j31kw0wuhar.jpg" alt="difference-1.5-2.0"></p>
<p>接下来好好分析上面新版本（2.0.1）的 run 方法的代码并配合比较旧版本（1.5.12）。</p>
<p><strong>1、configureHeadlessProperty()</strong>：设置 headless 模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = <span class="string">"java.awt.headless"</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">boolean</span> headless = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">configureHeadlessProperty</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(</span><br><span class="line">    SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(<span class="keyword">this</span>.headless)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>实际上是就是设置系统属性 java.awt.headless，该属性会被设置为 true。</p>
<p><strong>2、getRunListeners()</strong>：加载 SpringApplicationRunListener 对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">//<span class="doctag">TODO:</span>  xxx</span></span><br><span class="line">SpringApplicationRunListeners listeners = getRunListeners(args);<span class="comment">//初始化监听器</span></span><br><span class="line">listeners.starting();</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">  prepareContext(context, environment, listeners, applicationArguments, printedBanner);</span><br><span class="line">  refreshContext(context);</span><br><span class="line">  afterRefresh(context, applicationArguments);</span><br><span class="line">  listeners.started(context);</span><br><span class="line">  callRunners(context, applicationArguments);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">  listeners.running(context);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> SpringApplicationRunListeners <span class="title">getRunListeners</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">  Class&lt;?&gt;[] types = <span class="keyword">new</span> Class&lt;?&gt;[] &#123; SpringApplication.class, String[].class &#125;;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> SpringApplicationRunListeners(logger, getSpringFactoriesInstances(</span><br><span class="line">    SpringApplicationRunListener.class, types, <span class="keyword">this</span>, args));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的 getRunListeners() 中也利用 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringApplicationRunListener 的值，然后再将获取到的值作为参数传递到 SpringApplicationRunListeners 的构造方法中去创建对象。</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqxei8t4u6j31do0ow0z9.jpg" alt="2018-05-02_23-11-01"></p>
<p><strong>3、new DefaultApplicationArguments(args)</strong> ：获取启动时传入参数 args（main 方法传进来的参数） 并初始化为 ApplicationArguments 对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">DefaultApplicationArguments</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">  Assert.notNull(args, <span class="string">"Args must not be null"</span>);</span><br><span class="line">  <span class="keyword">this</span>.source = <span class="keyword">new</span> Source(args);</span><br><span class="line">  <span class="keyword">this</span>.args = args;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>4、prepareEnvironment(listeners, applicationArguments)</strong>：根据 listeners 和 applicationArguments 配置SpringBoot 应用的环境。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> ConfigurableEnvironment <span class="title">prepareEnvironment</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">  SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments)</span> </span>&#123;</span><br><span class="line">  <span class="comment">// Create and configure the environment</span></span><br><span class="line">  ConfigurableEnvironment environment = getOrCreateEnvironment();</span><br><span class="line">  configureEnvironment(environment, applicationArguments.getSourceArgs());</span><br><span class="line">  listeners.environmentPrepared(environment);</span><br><span class="line">  bindToSpringApplication(environment);</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.webApplicationType == WebApplicationType.NONE) &#123;</span><br><span class="line">    environment = <span class="keyword">new</span> EnvironmentConverter(getClassLoader())</span><br><span class="line">      .convertToStandardEnvironmentIfNecessary(environment);</span><br><span class="line">  &#125;</span><br><span class="line">  ConfigurationPropertySources.attach(environment);</span><br><span class="line">  <span class="keyword">return</span> environment;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//如果 environment 不为空，直接 get 到，否则创建</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> ConfigurableEnvironment <span class="title">getOrCreateEnvironment</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.environment != <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.environment;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.webApplicationType == WebApplicationType.SERVLET) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> StandardServletEnvironment();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> StandardEnvironment();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//配置环境</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configureEnvironment</span><span class="params">(ConfigurableEnvironment environment,String[] args)</span> </span>&#123;</span><br><span class="line">  configurePropertySources(environment, args);<span class="comment">//配置要使用的PropertySources</span></span><br><span class="line">  configureProfiles(environment, args);<span class="comment">//配置要使用的Profiles</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//将环境绑定到 SpringApplication</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">bindToSpringApplication</span><span class="params">(ConfigurableEnvironment environment)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    Binder.get(environment).bind(<span class="string">"spring.main"</span>, Bindable.ofInstance(<span class="keyword">this</span>));</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"Cannot bind to SpringApplication"</span>, ex);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>5、configureIgnoreBeanInfo(environment)</strong>：根据环境信息配置要忽略的 bean 信息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String IGNORE_BEANINFO_PROPERTY_NAME = <span class="string">"spring.beaninfo.ignore"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">configureIgnoreBeanInfo</span><span class="params">(ConfigurableEnvironment environment)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (System.getProperty(</span><br><span class="line">    CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == <span class="keyword">null</span>) &#123;</span><br><span class="line">    Boolean ignore = environment.getProperty(<span class="string">"spring.beaninfo.ignore"</span>,</span><br><span class="line">                                             Boolean.class, Boolean.TRUE);</span><br><span class="line">    System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,</span><br><span class="line">                       ignore.toString());</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>6、printBanner(environment)</strong>：打印标志，上面我已经说过了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Banner <span class="title">printBanner</span><span class="params">(ConfigurableEnvironment environment)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.bannerMode == Banner.Mode.OFF) &#123;	<span class="comment">//如果设置为 off，不打印 Banner</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  ResourceLoader resourceLoader = <span class="keyword">this</span>.resourceLoader != <span class="keyword">null</span> ? <span class="keyword">this</span>.resourceLoader</span><br><span class="line">    : <span class="keyword">new</span> DefaultResourceLoader(getClassLoader());</span><br><span class="line">  SpringApplicationBannerPrinter bannerPrinter = <span class="keyword">new</span> SpringApplicationBannerPrinter(</span><br><span class="line">    resourceLoader, <span class="keyword">this</span>.banner);</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.bannerMode == Mode.LOG) &#123;</span><br><span class="line">    <span class="keyword">return</span> bannerPrinter.print(environment, <span class="keyword">this</span>.mainApplicationClass, logger);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> bannerPrinter.print(environment, <span class="keyword">this</span>.mainApplicationClass, System.out);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>7、createApplicationContext()</strong>：根据应用类型来确定该 Spring Boot 项目应该创建什么类型的 ApplicationContext ，默认情况下，如果没有明确设置的应用程序上下文或应用程序上下文类，该方法会在返回合适的默认值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_WEB_CONTEXT_CLASS = <span class="string">"org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = <span class="string">"org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_CONTEXT_CLASS = <span class="string">"org.springframework.context.annotation.AnnotationConfigApplicationContext"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">protected</span> ConfigurableApplicationContext <span class="title">createApplicationContext</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  Class&lt;?&gt; contextClass = <span class="keyword">this</span>.applicationContextClass;</span><br><span class="line">  <span class="keyword">if</span> (contextClass == <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">switch</span> (<span class="keyword">this</span>.webApplicationType) &#123;	<span class="comment">//根据应用程序的类型来初始化容器</span></span><br><span class="line">        <span class="keyword">case</span> SERVLET:	<span class="comment">//servlet 应用程序</span></span><br><span class="line">          contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> REACTIVE:	<span class="comment">//reactive 应用程序</span></span><br><span class="line">          contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:		<span class="comment">//默认</span></span><br><span class="line">          contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(</span><br><span class="line">    <span class="string">"Unable create a default ApplicationContext,please specify an 		    ApplicationContextClass"</span>,ex);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//最后通过Spring的工具类 BeanUtils 初始化容器类 bean</span></span><br><span class="line">  <span class="keyword">return</span> (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>来看看在 1.5.12 中是怎么样的？</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6tx7lchj31kw0nw4gr.jpg" alt="createApplicationContext"></p>
<p><strong>8、exceptionReporters = getSpringFactoriesInstances(      SpringBootExceptionReporter.class,      new Class[] { ConfigurableApplicationContext.class }, context)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> &lt;T&gt; <span class="function">Collection&lt;T&gt; <span class="title">getSpringFactoriesInstances</span><span class="params">(Class&lt;T&gt; type,</span></span></span><br><span class="line"><span class="function"><span class="params">            Class&lt;?&gt;[] parameterTypes, Object... args)</span> </span>&#123;</span><br><span class="line">  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();</span><br><span class="line">  <span class="comment">// Use names and ensure unique to protect against duplicates</span></span><br><span class="line">  Set&lt;String&gt; names = <span class="keyword">new</span> LinkedHashSet&lt;&gt;(</span><br><span class="line">    SpringFactoriesLoader.loadFactoryNames(type, classLoader));</span><br><span class="line">  List&lt;T&gt; instances = createSpringFactoriesInstances(type, parameterTypes,</span><br><span class="line">       classLoader, args, names);<span class="comment">//根据类型 key 为 SpringBootExceptionReporter 去加载</span></span><br><span class="line">  AnnotationAwareOrderComparator.sort(instances);<span class="comment">//对实例排序</span></span><br><span class="line">  <span class="keyword">return</span> instances;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里也是通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringBootExceptionReporter 的全类名的 value 值。</p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tp9y81j31kw0tfdqv.jpg" alt="springbootexception"></p>
<p><strong>9、prepareContext(context, environment, listeners, applicationArguments, printedBanner)</strong>：完成整个容器的创建与启动以及 bean 的注入功能。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//装配 Context</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">prepareContext</span><span class="params">(ConfigurableApplicationContext context,</span></span></span><br><span class="line"><span class="function"><span class="params">   ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,</span></span></span><br><span class="line"><span class="function"><span class="params">   ApplicationArguments applicationArguments, Banner printedBanner)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//将之前准备好的 environment 设置给创建好的 ApplicationContext 使用</span></span><br><span class="line">  context.setEnvironment(environment);</span><br><span class="line">  <span class="comment">//1、</span></span><br><span class="line">  postProcessApplicationContext(context);</span><br><span class="line">  <span class="comment">//2、</span></span><br><span class="line">  applyInitializers(context);</span><br><span class="line">  listeners.contextPrepared(context);</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.logStartupInfo) &#123;<span class="comment">//启动日志</span></span><br><span class="line">    logStartupInfo(context.getParent() == <span class="keyword">null</span>);</span><br><span class="line">    logStartupProfileInfo(context);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// Add boot specific singleton beans</span></span><br><span class="line">  context.getBeanFactory().registerSingleton(<span class="string">"springApplicationArguments"</span>,</span><br><span class="line">                                             applicationArguments);</span><br><span class="line">  <span class="keyword">if</span> (printedBanner != <span class="keyword">null</span>) &#123;</span><br><span class="line">    context.getBeanFactory().registerSingleton(<span class="string">"springBootBanner"</span>, printedBanner);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// Load the sources</span></span><br><span class="line">  Set&lt;Object&gt; sources = getAllSources();</span><br><span class="line">  Assert.notEmpty(sources, <span class="string">"Sources must not be empty"</span>);</span><br><span class="line">  <span class="comment">//3、</span></span><br><span class="line">  load(context, sources.toArray(<span class="keyword">new</span> Object[<span class="number">0</span>]));</span><br><span class="line">  listeners.contextLoaded(context);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>1）、postProcessApplicationContext(context)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String CONFIGURATION_BEAN_NAME_GENERATOR = <span class="string">"org.springframework.context.annotation.internalConfigurationBeanNameGenerator"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">postProcessApplicationContext</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.beanNameGenerator != <span class="keyword">null</span>) &#123;</span><br><span class="line">    context.getBeanFactory().registerSingleton(</span><br><span class="line">      AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,</span><br><span class="line">      <span class="keyword">this</span>.beanNameGenerator);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.resourceLoader != <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (context <span class="keyword">instanceof</span> GenericApplicationContext) &#123;</span><br><span class="line">      ((GenericApplicationContext) context)</span><br><span class="line">      .setResourceLoader(<span class="keyword">this</span>.resourceLoader);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (context <span class="keyword">instanceof</span> DefaultResourceLoader) &#123;</span><br><span class="line">      ((DefaultResourceLoader) context)</span><br><span class="line">      .setClassLoader(<span class="keyword">this</span>.resourceLoader.getClassLoader());</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>该方法对 context 进行了预设置，设置了 ResourceLoader 和 ClassLoader，并向 bean 工厂中添加了一个beanNameGenerator 。</p>
<p><strong>2）、applyInitializers(context)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">applyInitializers</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">for</span> (ApplicationContextInitializer initializer : getInitializers()) &#123;</span><br><span class="line">    Class&lt;?&gt; requiredType = GenericTypeResolver.resolveTypeArgument(</span><br><span class="line">      initializer.getClass(), ApplicationContextInitializer.class);</span><br><span class="line">    Assert.isInstanceOf(requiredType, context, <span class="string">"Unable to call initializer."</span>);</span><br><span class="line">    initializer.initialize(context);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在刷新之前将任何 ApplicationContextInitializer 应用于上下文</p>
<p><strong>3)、load(context, sources.toArray(new Object[0]))</strong></p>
<p>主要是加载各种 beans 到 ApplicationContext 对象中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">load</span><span class="params">(ApplicationContext context, Object[] sources)</span> </span>&#123;</span><br><span class="line">  BeanDefinitionLoader loader = createBeanDefinitionLoader( <span class="comment">//2</span></span><br><span class="line">    getBeanDefinitionRegistry(context), sources);<span class="comment">// 1</span></span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.beanNameGenerator != <span class="keyword">null</span>) &#123;</span><br><span class="line">    loader.setBeanNameGenerator(<span class="keyword">this</span>.beanNameGenerator);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.resourceLoader != <span class="keyword">null</span>) &#123;</span><br><span class="line">    loader.setResourceLoader(<span class="keyword">this</span>.resourceLoader);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.environment != <span class="keyword">null</span>) &#123;</span><br><span class="line">    loader.setEnvironment(<span class="keyword">this</span>.environment);</span><br><span class="line">  &#125;</span><br><span class="line">  loader.load();<span class="comment">//3</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>(1)、getBeanDefinitionRegistry(context)</strong></p>
<p>获取 bean 定义注册表</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> BeanDefinitionRegistry <span class="title">getBeanDefinitionRegistry</span><span class="params">(ApplicationContext context)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (context <span class="keyword">instanceof</span> BeanDefinitionRegistry) &#123;</span><br><span class="line">    <span class="keyword">return</span> (BeanDefinitionRegistry) context;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (context <span class="keyword">instanceof</span> AbstractApplicationContext) &#123;</span><br><span class="line">    <span class="keyword">return</span> (BeanDefinitionRegistry) ((AbstractApplicationContext) context)</span><br><span class="line">      .getBeanFactory();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"Could not locate BeanDefinitionRegistry"</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>(2)、createBeanDefinitionLoader()</strong></p>
<p>通过 BeanDefinitionLoader 的构造方法把参数（注册表、资源）传进去，然后创建 BeanDefinitionLoader。</p>
<p><strong>(3)、load()</strong></p>
<p>把资源全部加载。</p>
<p><strong>10、refreshContext(context)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">refreshContext</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">  refresh(context);<span class="comment">//1</span></span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.registerShutdownHook) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      context.registerShutdownHook();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (AccessControlException ex) &#123;</span><br><span class="line">      <span class="comment">// Not allowed in some environments.</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//刷新底层的 ApplicationContext</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">refresh</span><span class="params">(ApplicationContext applicationContext)</span> </span>&#123;</span><br><span class="line">  Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);</span><br><span class="line">  ((AbstractApplicationContext) applicationContext).refresh();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>refreshContext(context) 方法又调用了 refresh(context)。在调用了 refresh(context) 方法之后，调用了 registerShutdownHook 方法。继续看它的 refresh 方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">refresh</span><span class="params">()</span> <span class="keyword">throws</span> BeansException, IllegalStateException </span>&#123;</span><br><span class="line">  <span class="keyword">synchronized</span> (<span class="keyword">this</span>.startupShutdownMonitor) &#123;</span><br><span class="line">    <span class="comment">// Prepare this context for refreshing.</span></span><br><span class="line">    prepareRefresh();</span><br><span class="line">    <span class="comment">// Tell the subclass to refresh the internal bean factory.</span></span><br><span class="line">    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();</span><br><span class="line">    <span class="comment">// Prepare the bean factory for use in this context.</span></span><br><span class="line">    prepareBeanFactory(beanFactory);</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="comment">// Allows post-processing of the bean factory in context subclasses.</span></span><br><span class="line">      postProcessBeanFactory(beanFactory);</span><br><span class="line">      <span class="comment">// Invoke factory processors registered as beans in the context.</span></span><br><span class="line">      invokeBeanFactoryPostProcessors(beanFactory);</span><br><span class="line">      <span class="comment">// Register bean processors that intercept bean creation.</span></span><br><span class="line">      registerBeanPostProcessors(beanFactory);</span><br><span class="line">      <span class="comment">// Initialize message source for this context.</span></span><br><span class="line">      initMessageSource();</span><br><span class="line">      <span class="comment">// Initialize event multicaster for this context.</span></span><br><span class="line">      initApplicationEventMulticaster();</span><br><span class="line">      <span class="comment">// Initialize other special beans in specific context subclasses.</span></span><br><span class="line">      onRefresh();</span><br><span class="line">      <span class="comment">// Check for listener beans and register them.</span></span><br><span class="line">      registerListeners();</span><br><span class="line">      <span class="comment">// Instantiate all remaining (non-lazy-init) singletons.</span></span><br><span class="line">      finishBeanFactoryInitialization(beanFactory); <span class="comment">//1</span></span><br><span class="line">      <span class="comment">// Last step: publish corresponding event.</span></span><br><span class="line">      finishRefresh();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (BeansException ex) &#123;</span><br><span class="line">      。。。</span><br><span class="line">        <span class="comment">// Destroy already created singletons to avoid dangling resources.</span></span><br><span class="line">        destroyBeans();</span><br><span class="line">      <span class="comment">// Reset 'active' flag.</span></span><br><span class="line">      cancelRefresh(ex);</span><br><span class="line">      <span class="comment">// Propagate exception to caller.</span></span><br><span class="line">      <span class="keyword">throw</span> ex;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">      <span class="comment">// Reset common introspection caches in Spring's core, since we</span></span><br><span class="line">      <span class="comment">// might not ever need metadata for singleton beans anymore...</span></span><br><span class="line">      resetCommonCaches();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>到这里，我们就看见重点了，仔细看上的注释，正在做各种初始化工作，而今天我们关注的重点就是方法 finishBeanFactoryInitialization(beanFactory)。该方法进行了非懒加载 beans 的初始化工作。现在我们进入该方法内部，一探究竟。</p>
<p><img src="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6tli7pjj31kw1757h0.jpg" alt="finishbeanFactoryini"></p>
<p>看上图方法中的最后一步，调用了 beanFactory 的 preInstantiateSingletons() 方法。此处的 beanFactory 是哪个类的实例对象呢？</p>
<p><img src="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6xir0iaj31kw0urjuy.jpg" alt="2018-05-02_16-17-50"></p>
<p>可以看到 ConfigurableListableBeanFactory 接口的实现类只有 DefaultListableBeanFactory，我们看下实现类中的 preInstantiateSingletons 方法是怎么做的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">preInstantiateSingletons</span><span class="params">()</span> <span class="keyword">throws</span> BeansException </span>&#123;</span><br><span class="line">  <span class="comment">// Iterate over a copy to allow for init methods which in turn register new bean definitions.</span></span><br><span class="line">  <span class="comment">// While this may not be part of the regular factory bootstrap, it does otherwise work fine.</span></span><br><span class="line">  List&lt;String&gt; beanNames = <span class="keyword">new</span> ArrayList&lt;&gt;(<span class="keyword">this</span>.beanDefinitionNames);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Trigger initialization of all non-lazy singleton beans...</span></span><br><span class="line">  <span class="keyword">for</span> (String beanName : beanNames) &#123;</span><br><span class="line">    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);</span><br><span class="line">    <span class="keyword">if</span> (!bd.isAbstract() &amp;&amp; bd.isSingleton() &amp;&amp; !bd.isLazyInit()) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isFactoryBean(beanName)) &#123;</span><br><span class="line">        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);</span><br><span class="line">        <span class="keyword">if</span> (bean <span class="keyword">instanceof</span> FactoryBean) &#123;</span><br><span class="line">          <span class="keyword">final</span> FactoryBean&lt;?&gt; factory = (FactoryBean&lt;?&gt;) bean;</span><br><span class="line">          <span class="keyword">boolean</span> isEagerInit;</span><br><span class="line">         <span class="keyword">if</span> (System.getSecurityManager() != <span class="keyword">null</span> &amp;&amp; factory <span class="keyword">instanceof</span> SmartFactoryBean)&#123;</span><br><span class="line">            isEagerInit = AccessController.doPrivileged((PrivilegedAction&lt;Boolean&gt;)</span><br><span class="line">             ((SmartFactoryBean&lt;?&gt;) factory)::isEagerInit, getAccessControlContext());</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            isEagerInit = (factory <span class="keyword">instanceof</span> SmartFactoryBean &amp;&amp;</span><br><span class="line">                           ((SmartFactoryBean&lt;?&gt;) factory).isEagerInit());</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">if</span> (isEagerInit) &#123;</span><br><span class="line">            getBean(beanName);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        getBean(beanName);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Trigger post-initialization callback for all applicable beans...</span></span><br><span class="line">  <span class="keyword">for</span> (String beanName : beanNames) &#123;</span><br><span class="line">    Object singletonInstance = getSingleton(beanName);</span><br><span class="line">    <span class="keyword">if</span> (singletonInstance <span class="keyword">instanceof</span> SmartInitializingSingleton) &#123;</span><br><span class="line">      <span class="keyword">final</span> SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;</span><br><span class="line">      <span class="keyword">if</span> (System.getSecurityManager() != <span class="keyword">null</span>) &#123;</span><br><span class="line">        AccessController.doPrivileged((PrivilegedAction&lt;Object&gt;) () -&gt; &#123;</span><br><span class="line">          smartSingleton.afterSingletonsInstantiated();</span><br><span class="line">          <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;, getAccessControlContext());</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        smartSingleton.afterSingletonsInstantiated();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>从上面的代码中可以看到很多调用了 getBean(beanName) 方法，跟踪此方法进去后，最终发现 getBean 调用了AbstractBeanFactory 类的 doGetBean(xxx) 方法，doGetBean(xxx) 方法中有这么一段代码：</p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tr2ukqj31je1fegwm.jpg" alt="2018-05-02_17-17-39"></p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6xjtn0hj31ja17g15o.jpg" alt="2018-05-02_17-19-31"></p>
<p>但是 createBean() 方法并没有得到实现，实现类在 AbstractAutowireCapableBeanFactory 中。这才是创建 bean 的核心方法。</p>
<p><img src="https://ws3.sinaimg.cn/large/006tNc79gy1fqx6toc4dxj31kw1bana4.jpg" alt="createBean"></p>
<p>不知不觉，代码看的越来越深，感觉思维都差点回不去 run 方法了，切回大脑的上下文线程到 run 方法去。</p>
<p><strong>11、afterRefresh(context, applicationArguments)</strong>：在上下文刷新后调用该方法，其内部没有做任何操作。</p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6tnnz8vj31bs0pkgrg.jpg" alt="2018-05-02_17-43-23"></p>
<p>发现没做任何操作了之后，就觉得有点奇怪，所以把当前版本和 1.5.12  对比了下，发现：</p>
<p><img src="https://ws4.sinaimg.cn/large/006tNc79gy1fqx6ts33l2j31kw0witww.jpg" alt="afterRefresh"></p>
<p>在 1.5.12 中的 afterRefresh() 方法中调用了 callRunners() 方法，但是在 2.0.1 版本中的 run 方法中调用了 callRunners () 方法:</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6xmgbpvj31kw0x8hc4.jpg" alt="2018-05-02_17-57-52"></p>
<p>这里不得不说 SpringApplicationRunListeners 在 2.0.1 中的改变：</p>
<p><img src="https://ws1.sinaimg.cn/large/006tNc79gy1fqx6tq6fzhj31kw0y5azk.jpg" alt="2018-05-02_18-28-17"></p>
<p>可以发现在 run 方法中，SpringApplicationRunListeners 监听器的状态花生了变化，这也是通过对比不同版本的代码才知道的区别，所以说我们看源码需要多对比着看。</p>
<p>so，我们来看下这个 SpringApplicationRunListener 这个接口：</p>
<p><img src="https://ws2.sinaimg.cn/large/006tNc79gy1fqx6xla7afj31kw0unx1j.jpg" alt="2018-05-02_18-33-20"></p>
<p>started 状态：The context has been refreshed and the application has started but CommandLineRunner and ApplicationRunner have not been called</p>
<p>running 状态：Called immediately before the run method finishes, when the application context has been refreshed and all CommandLineRunner and ApplicationRunners have been called.</p>
<h3 id="相关文章"><a href="#相关文章" class="headerlink" title="相关文章"></a>相关文章</h3><p>1、<a href="http://www.54tianzhisheng.cn/2018/03/06/SpringBoot2-Migration-Guide/">Spring Boot 2.0系列文章(一)：Spring Boot 2.0 迁移指南</a></p>
<p>2、<a href="http://www.54tianzhisheng.cn/2018/03/06/SpringBoot2-new-features/">Spring Boot 2.0系列文章(二)：Spring Boot 2.0 新特性详解</a></p>
<p>3、<a href="http://www.54tianzhisheng.cn/2018/04/13/Spring_Boot_2.0_Configuration_Changelog/">Spring Boot 2.0系列文章(三)：Spring Boot 2.0 配置改变</a></p>
<p>4、<a href="http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/">Spring Boot 2.0系列文章(四)：Spring Boot 2.0 源码阅读环境搭建</a></p>
<p>5、<a href="http://www.54tianzhisheng.cn/2018/04/18/spring_boot2_project/">Spring Boot 2.0系列文章(五)：Spring Boot 2.0 项目源码结构预览</a></p>
<p>6、<a href="http://www.54tianzhisheng.cn/2018/04/19/SpringBootApplication-annotation/">Spring Boot 2.0系列文章(六)：Spring boot 2.0 中 SpringBootApplication 注解详解</a></p>
<p>7、<a href="http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/">Spring Boot 2.0系列文章(七)：SpringApplication 深入探索</a></p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本文从源码级别分析了 Spring Boot 应用程序的启动过程，着重看了 SpringApplication 类中的构造函数的初始化和其 run 方法内部实现，并把涉及到的流程代码都过了一遍。</p>
<p>感悟：有时候跟代码跟着跟着，发现越陷越深，好难跳出来！后面还需多向别人请教阅读源码的技巧！</p>
<h3 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h3><p>虽然源码很难，但随着不断的探索，源码在你面前将会一览无遗，享受这种探索后的成就感！加油！骚年！</p>
<p>自己本人能力有限，源码看的不多，上面如有不对的还请留言交流。</p>

      
      
        <div class="page-reward">
          <p><a href="javascript:void(0)" onclick="dashangToggle()" class="dashang">赏</a></p>
          <div class="hide_box"></div>
          <div class="shang_box">
            <a class="shang_close" href="javascript:void(0)" onclick="dashangToggle()">×</a>
            <div class="shang_tit">
              <p>纯属好玩</p>
            </div>
            <div class="shang_payimg">
              <img src="/img/alipayimg.jpg" alt="扫码支持" title="扫一扫" />
            </div>
              <div class="pay_explain">扫码打赏，你说多少就多少</div>
            <div class="shang_payselect">
              
                <div class="pay_item checked" data-id="alipay">
                  <span class="radiobox"></span>
                  <span class="pay_logo"><img src="/img/alipay.png" alt="支付宝" /></span>
                </div>
              
              
                <div class="pay_item" data-id="wechat">
                  <span class="radiobox"></span>
                  <span class="pay_logo"><img src="/img/weixin.png" alt="微信" /></span>
                </div>
              
            </div>
            <div class="shang_info">
              <p>打开<span id="shang_pay_txt">支付宝</span>扫一扫，即可进行扫码打赏哦</p>
            </div>
          </div>
        </div>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
        <script type="text/javascript">
          $(".pay_item").click(function(){
            $(this).addClass('checked').siblings('.pay_item').removeClass('checked');
            var dataid=$(this).attr('data-id');
            $(".shang_payimg img").attr("src","/img/"+dataid+"img.jpg");
            $("#shang_pay_txt").text(dataid=="alipay"?"支付宝":"微信");
          });
          function dashangToggle(){
            
            $(".hide_box").fadeToggle();
            $(".shang_box").fadeToggle();
          }
        </script>
      
    </div>
    
  </div>
  
    
    <div class="copyright">
        <p><span>本文标题:</span><a href="/2018/04/30/springboot_SpringApplication/">Spring Boot 2.0系列文章(七)：SpringApplication 深入探索</a></p>
        <p><span>文章作者:</span><a href="/" title="访问 zhisheng 的个人博客">zhisheng</a></p>
        <p><span>发布时间:</span>2018年04月30日 - 00时00分</p>
        <p><span>最后更新:</span>2018年11月22日 - 22时51分</p>
        <p>
            <span>原始链接:</span><a class="post-url" href="/2018/04/30/springboot_SpringApplication/" title="Spring Boot 2.0系列文章(七)：SpringApplication 深入探索">http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/</a>
            <span class="copy-path" data-clipboard-text="原文: http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/　　作者: zhisheng" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span>
            <script src="/js/clipboard.min.js"></script>
            <script> var clipboard = new Clipboard('.copy-path'); </script>
        </p>
        <p>
            <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/cn/" title="中国大陆 (CC BY-NC-SA 3.0 CN)" target = "_blank">"署名-非商用-相同方式共享 3.0"</a> 转载请保留原文链接及作者。
        </p>
    </div>



<nav id="article-nav">
  
    <a href="/2018/05/26/paper/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption"><</strong>
      <div class="article-nav-title">
        
          苦逼的毕业论文经历
        
      </div>
    </a>
  
  
    <a href="/2018/04/24/Distributed_lock/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">分布式锁看这篇就够了</div>
      <strong class="article-nav-caption">></strong>
    </a>
  
</nav>

  
</article>

    <div id="toc" class="toc-article">
    <strong class="toc-title">文章目录</strong>
    <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#关注我"><span class="toc-number">1.</span> <span class="toc-text">关注我</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#前言"><span class="toc-number">2.</span> <span class="toc-text">前言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#换个姿势"><span class="toc-number">3.</span> <span class="toc-text">换个姿势</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringApplication-初始化"><span class="toc-number">4.</span> <span class="toc-text">SpringApplication 初始化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#run-方法背后的秘密"><span class="toc-number">5.</span> <span class="toc-text">run 方法背后的秘密</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#相关文章"><span class="toc-number">6.</span> <span class="toc-text">相关文章</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#总结"><span class="toc-number">7.</span> <span class="toc-text">总结</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#最后"><span class="toc-number">8.</span> <span class="toc-text">最后</span></a></li></ol>
</div>
<input type="button" id="tocButton" value="隐藏目录"  title="点击按钮隐藏或者显示文章目录">

<script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
<script>
    var valueHide = "隐藏目录";
    var valueShow = "显示目录";

    if ($(".left-col").is(":hidden")) {
        $("#tocButton").attr("value", valueShow);
    }
    $("#tocButton").click(function() {
        if ($("#toc").is(":hidden")) {
            $("#tocButton").attr("value", valueHide);
            $("#toc").slideDown(320);
        }
        else {
            $("#tocButton").attr("value", valueShow);
            $("#toc").slideUp(350);
        }
    })
    if ($(".toc").length < 1) {
        $("#toc, #tocButton").hide();
    }
</script>





<div class="bdsharebuttonbox">
	<a href="#" class="fx fa-weibo bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
	<a href="#" class="fx fa-weixin bds_weixin" data-cmd="weixin" title="分享到微信"></a>
	<a href="#" class="fx fa-qq bds_sqq" data-cmd="sqq" title="分享到QQ好友"></a>
	<a href="#" class="fx fa-facebook-official bds_fbook" data-cmd="fbook" title="分享到Facebook"></a>
	<a href="#" class="fx fa-twitter bds_twi" data-cmd="twi" title="分享到Twitter"></a>
	<a href="#" class="fx fa-linkedin bds_linkedin" data-cmd="linkedin" title="分享到linkedin"></a>
	<a href="#" class="fx fa-files-o bds_copy" data-cmd="copy" title="分享到复制网址"></a>
</div>
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"2","bdSize":"24"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>




    
        <div id="gitments"></div>
<script src="/js/gitment.browser.js"></script>
<script>
    var gitment = new Gitment({
      id: window.location.pathname,
      owner: 'zhisheng',
      repo: 'zhisheng17.github.io',
      oauth: {
        client_id: '',
        client_secret: '',
      },
    })
    gitment.render('gitments')
</script>
    



    <div class="scroll" id="post-nav-button">
        
            <a href="/2018/05/26/paper/" title="上一篇: 苦逼的毕业论文经历">
                <i class="fa fa-angle-left"></i>
            </a>
        
        <a title="文章列表"><i class="fa fa-bars"></i><i class="fa fa-times"></i></a>
        
            <a href="/2018/04/24/Distributed_lock/" title="下一篇: 分布式锁看这篇就够了">
                <i class="fa fa-angle-right"></i>
            </a>
        
    </div>
    <ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/2019/01/06/Flink-Kafka-sink/">《从0到1学习Flink》—— Flink 写入数据到 Kafka</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/01/05/Flink-run/">《从0到1学习Flink》—— Flink 项目如何运行？</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/30/Flink-ElasticSearch-Sink/">《从0到1学习Flink》—— Flink 写入数据到 ElasticSearch</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/11/Flink-time/">《从0到1学习Flink》—— Flink 中几种 Time 详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/08/Flink-Stream-Windows/">《从0到1学习Flink》—— 介绍Flink中的Stream Windows</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/11/04/Flink-Data-transformation/">《从0到1学习Flink》—— Flink Data transformation(转换)</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/31/flink-create-sink/">《从0到1学习Flink》—— 如何自定义 Data Sink ？</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/30/flink-create-source/">《从0到1学习Flink》—— 如何自定义 Data Source ？</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/29/flink-sink/">《从0到1学习Flink》—— Data Sink 介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/28/flink-sources/">《从0到1学习Flink》—— Data Source 介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/27/flink-config/">《从0到1学习Flink》—— Flink 配置文件详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/13/flink-introduction/">《从0到1学习Flink》—— Apache Flink 介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/09/18/flink-install/">《从0到1学习Flink》—— Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/30/go-sync/">Go 并发——实现协程同步的几种方式</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/14/idea-remote-debug-elasticsearch/">教你如何在 IDEA 远程 Debug ElasticSearch</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/12/es-code03/">渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程（下）</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/11/es-code02/">渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程（上）</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/05/es-code01/">渣渣菜鸡的 ElasticSearch 源码解析 —— 环境搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/04/why-see-es-code/">渣渣菜鸡为什么要看 ElasticSearch 源码？</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/07/31/alipay02/">渣渣菜鸡的蚂蚁金服面试经历(二)</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/07/30/alipay01/">渣渣菜鸡的蚂蚁金服面试经历(一)</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/07/12/youzan/">渣渣菜鸡的有赞面试经历（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/20/java-8-date/">20 个案例教你在 Java 8 中如何处理日期和时间?</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/19/SimpleDateFormat/">SimpleDateFormat 如何安全的使用？</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/05/26/paper/">苦逼的毕业论文经历</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/30/springboot_SpringApplication/">Spring Boot 2.0系列文章(七)：SpringApplication 深入探索</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/24/Distributed_lock/">分布式锁看这篇就够了</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/19/SpringBootApplication-annotation/">Spring Boot 2.0系列文章(六)：Spring Boot 2.0中SpringBootApplication注解详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/18/spring_boot2_project/">Spring Boot 2.0系列文章(五)：Spring Boot 2.0 项目源码结构预览</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/15/springboot2_code/">Spring Boot 2.0系列文章(四)：Spring Boot 2.0 源码阅读环境搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/13/Spring_Boot_2.0_Configuration_Changelog/">Spring Boot 2.0系列文章(三)：Spring Boot 2.0 配置改变</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/27/blogs/">写这么多系列博客，怪不得找不到女朋友</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/06/SpringBoot2-new-features/">Spring Boot 2.0系列文章(二)：Spring Boot 2.0 新特性详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/06/SpringBoot2-Migration-Guide/">Spring Boot 2.0系列文章(一)：Spring Boot 2.0 迁移指南</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/04/springboot-vedio/">小马哥 《Java 微服务实践 - Spring Boot 系列》强烈推荐</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/04/springcloud-vedio/">小马哥 《Java 微服务实践 - Spring Cloud 系列》强烈推荐</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/28/Java-Memory-Model/">《深入理解 Java 内存模型》读书笔记</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/07/SpringBoot-RocketMQ/">Spring Boot系列文章（六）：SpringBoot RocketMQ 整合使用和监控</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/07/rocketmq-example/">RocketMQ系列文章（三）：RocketMQ 简单的消息示例</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/06/RocketMQ-install/">RocketMQ系列文章（二）：RocketMQ 安装及快速入门</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/05/RocketMQ/">RocketMQ系列文章（一）：RocketMQ 初探</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/28/RabbitMQ/">Spring Boot系列文章（五）：SpringBoot RabbitMQ 整合进阶版</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/27/SpringBoot-ActiveMQ/">Spring Boot系列文章（四）：SpringBoot ActiveMQ 整合使用</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/26/SpringBoot-RabbitMQ/">Spring Boot系列文章（三）：SpringBoot  RabbitMQ 整合使用</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/25/Docker-install/">Docker系列文章（二）：Mac 安装 Docker 及常用命令</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/24/mac/">MacBook Pro 初体验</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/17/SpringBoot-Admin/">Spring Boot系列文章（二）：SpringBoot Admin 使用指南</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/09/lombok/">Lombok 看这篇就够了</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/05/SpringBoot-Kafka/">Spring Boot系列文章（一）：SpringBoot Kafka 整合使用</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/04/Kafka/">Kafka 安装及快速入门</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/04/weixin/">为什么要重新运营以前的公众号呢？</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/27/consul-install/">Windows 下安装 Consul</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/25/ELK/">Elasticsearch 系列文章（五）：ELK 实时日志分析平台环境搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/18/hexo-yilia/">Hexo + yilia 搭建博客可能会遇到的所有疑问</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/13/Google-Developer-Days/">谷歌开发者大会收获满满，不去真 “可惜” 了</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/09/CodeMirror/">使用 CodeMirror 打造属于自己的在线代码编辑器</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/08/netty-01-env/">Netty系列文章（一）：Netty 源码阅读之初始环境搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/03/RestTemplate/">RestTemplate 详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/02/wx-01/">实习圈群里提问小记</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/11/26/Docker-harbor/">Docker系列文章（一）：基于 Harbor 搭建 Docker 私有镜像仓库</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/11/18/flow-control/">基于分布式环境下限流系统的设计</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/11/18/Money-management/">谈谈我的理财</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/11/11/recommended-books/">送你一份双十一剁手书单【墙裂推荐】</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/11/11/Maven-dependencies-dependencyManagement/">Maven 中 dependencies 与 dependencyManagement 的区别</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/28/Data-Desensitization/">小白谈数据脱敏</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/21/HBase-metrics/">HBase 集群监控</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/18/ElasticSearch-nodes-metrics/">Elasticsearch 系列文章（四）：ElasticSearch 单个节点监控</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/15/ElasticSearch-cluster-health-metrics/">Elasticsearch 系列文章（三）：ElasticSearch 集群监控</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/14/Nexus3-Maven/">Centos7 搭建最新 Nexus3 Maven 私服</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/14/JsonPath/">JsonPath —— JSON 解析神器</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/09/23/Guava-limit/">Google Guava 缓存实现接口的限流</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/09/17/Interview-summary/">面试过阿里等互联网大公司，我知道了这些套路</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/09/15/linux-lua-lfs-install/">Linux 下 lua 开发环境安装及安装 luafilesystem</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/09/09/Elasticsearch-install/">Elasticsearch 系列文章（二）：全文搜索引擎 Elasticsearch 集群搭建入门教程</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/09/08/Elasticsearch-analyzers/">Elasticsearch 系列文章（一）：Elasticsearch 默认分词器和中分分词器之间的比较及使用方法</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/28/recommend-books/">那些年我看过的书 —— 致敬我的大学生活 —— Say Good Bye ！</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/18/Ubuntu-install-Nginx/">Ubuntu16.10 安装 Nginx</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/11/most-success/">马云热血励志演讲《最伟大的成功》</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/08/android-projects/">源码大招：不服来战！撸这些完整项目，你不牛逼都难！</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/05/Nginx/">Nginx 基本知识快速入门</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/04/alibaba/">秋招第三站 —— 内推阿里（一面）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/04/yaxin/">秋招第一站 —— 亚信科技</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/08/04/iqiyi/">秋招第二站 —— 内推爱奇艺（一面二面）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/29/ThreadPool/">Java 线程池艺术探索</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/25/Java-performance-tuning/">Java 性能调优需要格外注意的细节</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/21/Spring-MVC03/">Spring MVC系列文章（五）：看透 Spring MVC 源代码分析与实践 ——  Spring MVC 组件分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/14/Spring-MVC01/">Spring MVC系列文章（三）：看透 Spring MVC 源代码分析与实践 ——  网站基础知识</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/14/Spring-MVC02/">Spring MVC系列文章（四）：看透 Spring MVC 源代码分析与实践 ——  俯视 Spring MVC</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/09/servlet/">通过源码详解 Servlet</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/28/Velocity-foreach/">Velocity 循环指令一种好的解决方法</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/23/java-io/">Java IO流学习超详细总结（图文并茂）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/23/AJAX/">AJAX 学习</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/20/Java-error1/">java.sql.SQLException Field 'id' doesn't have a default value</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/19/中缀表达式转换成前缀和后缀表达式这类题目的超实用解题技巧/">中缀表达式转换成前缀和后缀表达式这类题目的超实用解题技巧</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/18/Bootstrap入门需掌握的知识点（二）/">Bootstrap入门需掌握的知识点（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/18/Bootstrap入门需掌握的知识点（一）/">Bootstrap入门需掌握的知识点（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/18/循环队列的相关条件和公式/">循环队列的相关条件和公式</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/17/详解 Filter 过滤器/">详解 Filter 过滤器</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/17/blog-talk/">搭建一个博客项目后的碎碎念</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/17/详细深入分析 Java ClassLoader 工作机制/">详细深入分析 Java ClassLoader 工作机制</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/16/通过项目逐步深入了解Spring MVC（一）/">通过项目逐步深入了解Spring MVC（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/15/通过项目逐步深入了解Mybatis(四)/">通过项目逐步深入了解Mybatis（四）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/14/通过项目逐步深入了解Mybatis(三)/">通过项目逐步深入了解Mybatis（三）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Hexo-yilia-toc/">Hexo + yilia 主题实现文章目录</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/HashMap-Hashtable/">HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比较</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Spring MVC+Hibernate JPA搭建的博客系统项目中所遇到的坑/">Spring MVC系列文章（二）：Spring MVC+Hibernate JPA搭建的博客系统项目中所遇到的坑</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统/">Spring MVC系列文章（一）：Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统 Demo</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Java-Thread/">《Java 多线程编程核心技术》学习笔记及总结</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Python爬虫实战之爬取糗事百科段子/">Python爬虫实战之爬取糗事百科段子</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/通过项目逐步深入了解Mybatis(二)/">通过项目逐步深入了解Mybatis（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Pyspider框架 —— Python爬虫实战之爬取 V2EX 网站帖子/">Pyspider框架 —— Python爬虫实战之爬取 V2EX 网站帖子</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/MySQL-select-good/">MySQL 处理海量数据时的一些优化查询速度方法</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/MyBatis-foreach/">MyBatis的foreach语句详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Java连接Oracle数据库的三种连接方式/">Java连接Oracle数据库的三种连接方式</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/【字符串】判断两字符串是否互为旋转词？/">【字符串】判断两字符串是否互为旋转词？</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/【字符串】字符串逆序/">字符串</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/feiji/">记录下自己第一次坐飞机的感受</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/JVM性能调优监控工具jps、jstack、jmap、jhat、jstat等使用详解/">JVM性能调优监控工具jps、jstack、jmap、jhat、jstat等使用详解</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Java-16-lession/">《疯狂 Java 突破程序员基本功的 16 课》读书笔记</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/奇怪的Java题：为什么128 == 128返回为False，而127 == 127会返回为True-/">奇怪的Java题：为什么128 == 128返回为False，而127 == 127会返回为True?</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/利用Github Page 搭建个人博客网站/">利用Github Page 搭建个人博客网站</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/深入分析 Java Web 中的中文编码问题/">深入分析 Java Web 中的中文编码问题</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/程序访问文件的几种方式/">程序访问文件的几种方式</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/深度探究Java 中 finally 语句块/">深度探究Java 中 finally 语句块</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/解决jdk1.8中发送邮件失败（handshake_failure）问题/">解决jdk1.8中发送邮件失败（handshake_failure）问题</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/java-var/">从对象深入分析 Java 中实例变量和类变量的区别</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/String-new/">关于String s = new String("xyz"); 创建几个对象的问题</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/java读取文件/">Java读取文件</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Java NIO 系列教程/">Java NIO 系列教程</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/13/Python爬虫实战之爬取百度贴吧帖子/">Python爬虫实战之爬取百度贴吧帖子</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/12/通过项目逐步深入了解Mybatis(一)/">通过项目逐步深入了解Mybatis（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/02/poetry2/"> 六月 —— 愿你做最美好的自己！</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/05/12/poetry/">最近很火的鸡汤，分享给大家</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/04/13/Hexo-yilia-changyan/">Github pages + Hexo 博客 yilia 主题使用畅言评论系统</a></li></ul>
    <script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
    <script>
        $(".post-list").addClass("toc-article");
        $(".post-list-item a").attr("target","_blank");
        $("#post-nav-button > a:nth-child(2)").click(function() {
            $(".fa-bars, .fa-times").toggle();
            $(".post-list").toggle(300);
            if ($(".toc").length > 0) {
                $("#toc, #tocButton").toggle(200, function() {
                    if ($(".switch-area").is(":visible")) {
                        $("#tocButton").attr("value", valueHide);
                        }
                    })
            }
            else {
            }
        })
    </script>



    <script>
        
    </script>
</div>
      <footer id="footer">
    <div class="outer">
        <div id="footer-info">
            <div class="footer-left">
                &copy; 2019 zhisheng
            </div>
        </div>
        
            <div class="visit">
                
                    <span id="busuanzi_container_site_pv" style='display:none'>
                        <span id="site-visit" >本站总访问量: 
                            <span id="busuanzi_value_site_pv"></span>
                        </span>
                    </span>
                
                
                    <span>, </span>
                
                
                    <span id="busuanzi_container_page_pv" style='display:none'>
                        <span id="page-visit">本文总阅读量: 
                            <span id="busuanzi_value_page_pv"></span>
                        </span>
                    </span>
                
            </div>
        
    </div>
</footer>

    </div>
    <script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
<script src="/js/main.js"></script>

    <script>
        $(document).ready(function() {
            var backgroundnum = 24;
            var backgroundimg = "url(/background/bg-x.jpg)".replace(/x/gi, Math.ceil(Math.random() * backgroundnum));
            $("#mobile-nav").css({"background-image": backgroundimg,"background-size": "cover","background-position": "center"});
            $(".left-col").css({"background-image": backgroundimg,"background-size": "cover","background-position": "center"});
        })
    </script>




	<script>
	var _hmt = _hmt || [];
	(function() {
	  var hm = document.createElement("script");
	  hm.src = "https://hm.baidu.com/hm.js?c41be5a0c9f014e977695f66c065b5d3";
	  var s = document.getElementsByTagName("script")[0]; 
	  s.parentNode.insertBefore(hm, s);
	})();
	</script>


<div class="scroll" id="scroll">
    <a href="#"><i class="fa fa-arrow-up"></i></a>
    <a href="#comments"><i class="fa fa-comments-o"></i></a>
    <a href="#footer"><i class="fa fa-arrow-down"></i></a>
</div>
<script>
    $(document).ready(function() {
        if ($("#comments").length < 1) {
            $("#scroll > a:nth-child(2)").hide();
        };
    })
</script>

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js">
</script>

  <script language="javascript">
    $(function() {
        $("a[title]").each(function() {
            var a = $(this);
            var title = a.attr('title');
            if (title == undefined || title == "") return;
            a.data('title', title).removeAttr('title').hover(

            function() {
                var offset = a.offset();
                $("<div id=\"anchortitlecontainer\"></div>").appendTo($("body")).html(title).css({
                    top: offset.top - a.outerHeight() - 15,
                    left: offset.left + a.outerWidth()/2 + 1
                }).fadeIn(function() {
                    var pop = $(this);
                    setTimeout(function() {
                        pop.remove();
                    }, pop.text().length * 800);
                });
            }, function() {
                $("#anchortitlecontainer").remove();
            });
        });
    });
</script>


  </div>
</body>
</html>